/*********************************************************************************
 *      Copyright:  (C) 2025 ZYT
 *                  All rights reserved.
 *
 *       Filename:  pack.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(01/05/25)
 *         Author:  Zhang yuting<zhangyuting@163.com>
 *      ChangeLog:  1, Release initial version on "01/05/25 16:33:30"
 *                 
 ********************************************************************************/
#include "pack.h"

int pack_data(packet_t *pack, char *data, int bytes )
{
	if( NULL == pack)
	{
		log_error("pointer [pack] is NULL\n");
		return -1;
	}

	memset(data, 0, bytes);

	snprintf(data, bytes, "sn:%s|time:%s|temp:%f", pack->dev_sn, pack->dev_time, pack->dev_temp);

	log_debug("pack_data successfully!\n");
	return 0;
}

int unpack_data(uint8_t *data, packet_t *pack)
{
	if( NULL == data)
	{
		log_error("pointer [data] is NULL");
		return -1;
	}

	memset(pack, 0, sizeof(*pack));

	int parsed_len;
	int parsed=sscanf(data, "sn:%31[^|]|time:%31[^|]|temp:%f%n", pack->dev_sn, pack->dev_time, &pack->dev_temp, &parsed_len);
	
	if (parsed != 3 || data[parsed_len] != '\0') 
	{
		log_error("Parse failed (expected 3, got %d): %s\n", parsed_len, data);
	    return -3;
	}
	
	log_debug("unpack_data successfully!\n");
	return 0;
}
/*  
int unpack_data(uint8_t *buf, packet_t *data)
{
	int         k = 0;
	char        *str = NULL;

	if( !buf || !data )
	{
		log_warn("arguments is NULL");
		return -1;
	}

	str = strtok(buf, "=");
	while ( str )
	{
		str = strtok(NULL, "|");
		if ( k == 0 )
		{
			snprintf(data->dev_sn, sizeof(data->dev_sn), "%s", str);
		}
		else if ( k == 1 )
		{
			snprintf(data->dev_time, sizeof(data->dev_time), "%s", str);
		}
		else if ( k == 2)
		{
			float       temp_value = atof(str);
			snprintf(data->dev_temp, sizeof(data->dev_temp), "%.4f", temp_value);
		}
		++k;
		str = strtok(NULL, "=");
	}

	k = 0;
	return 0;
}
*/

int unpack_json(uint8_t *buf, packet_t *data) 
{
	cJSON *root = NULL;
	cJSON *temp = NULL;

	if (!buf || !data)
	{
		log_warn("arguments is NULL");
		return -1;
	}

	root = cJSON_Parse((const char*)buf);  // 强制类型转换
	if (!root)
	{
		log_error("JSON parse failed");
		return -2;
	}

	// 提取 "sn" 字段
	temp = cJSON_GetObjectItem(root, "sn");
	
	if (!temp || !cJSON_IsString(temp)) 
	{  // 检查存在性及类型
		log_error("Invalid/missing 'sn' field");
		cJSON_Delete(root);
		return -3;
	}
	
	strncpy(data->dev_sn, temp->valuestring, MAX_SN_LEN - 1);
	data->dev_sn[MAX_SN_LEN - 1] = '\0';

	// 提取 "temperature" 字段
	temp = cJSON_GetObjectItem(root, "temperature");
	
	if (!temp || !cJSON_IsNumber(temp)) 
	{  // 检查存在性及类型
		log_error("Invalid/missing 'temperature' field");
		cJSON_Delete(root);
		return -4;
	}
	data->dev_temp = temp->valuedouble;  // 直接取数值

	cJSON_Delete(root);
	return 0;
}


int unpack_tlv(uint8_t *buf, packet_t *data)
{
	char        *str = NULL;
	char        temp_str[32];
	int         tag_temperature = 1;
	uint16_t    crc_check;

	if( !buf || !data )
	{
		log_warn("arguments is NULL");
		return -1;
	}

	//Header
	uint16_t header = ntohs(*(uint16_t *)buf);
	if ( header != 0xFEDD )
	{
		log_error("Header failure\n");
		return -1;
	}

	//Tag
	uint8_t tag = buf[2];
	if ( tag != tag_temperature )
	{
		log_error("Tag failure\n");
		return -1;
	}

	//Length
	uint16_t length = (*(uint16_t *)(buf + 3));

	//Valure:ID
	char sn[10] = {0};
	memcpy(sn, buf + 5, 10);

	//Valure:TIME
	uint8_t year = buf[15];             // 年 - 2000
	uint8_t month = buf[16];            // 月
	uint8_t day = buf[17];              //日
	uint8_t hour = buf[18];             //时
	uint8_t minute = buf[19];           // 分
	uint8_t second = buf[20];           // 秒

	uint8_t temp_int = buf[21];      // 整数部分
	uint8_t temp_decimal1 = buf[22]; // 小数部分 ×10000
	uint8_t temp_decimal2 = buf[23]; // 小数部分 ×10000

	//CRC校验
	uint16_t crc = ntohs(*(uint16_t *)(buf + 24));
	crc_check = crc_itu_t(buf, length+5);

	if ( crc != crc_check )
	{
		log_error("CRC failure\nCRC16: 0x%04X\nCRC16_check: 0x%04X\n", crc, crc_check);
		return -1;
	}

	strncpy(data->dev_sn, sn, sizeof(data->dev_sn));
	snprintf(data->dev_time, sizeof(data->dev_time),
			"%04d%02d%02d %02d:%02d:%02d",year + 2000, month, day, hour, minute, second);
	snprintf(data->dev_temp, sizeof(data->dev_temp), "%d.%02d%02d", temp_int, temp_decimal1, temp_decimal2);

	return 0;
}

static uint16_t crc_itu_t(const uint8_t *data, size_t length)
{
	uint16_t          crc = 0xFFFF;
	size_t            i, j;

	for (i=0; i<length; i++)
	{
		crc ^= ((uint16_t)data[i] << 8);

		for(j=0; j<8; j++)
		{
			if (crc & 0x8000)
			{
				crc = (crc << 1) ^ CRC16_ITU_T_POLY;
			}
			else
			{
				crc <<= 1;
			}
		}
	}

	return crc;
}
